/*
**
** File: utassert.h
**
** $Id: utassert.h 1.4 2015/06/16 16:02:14EDT sstrege Exp  $
**
** Copyright 2012-2013 United States Government as represented by the 
** Administrator of the National Aeronautics and Space Administration. 
** All Other Rights Reserved.  
**
** This software was created at NASA's Goddard Space Flight Center.
** This software is governed by the NASA Open Source Agreement and may be 
** used, distributed and modified only pursuant to the terms of that 
** agreement.
**
** Purpose: This code implements a standard set of asserts for use in unit tests.
**
** $Log: utassert.h  $
** Revision 1.4 2015/06/16 16:02:14EDT sstrege 
** Added copyright information
** Revision 1.3 2015/03/17 18:13:15EDT czogby 
** --- Added comments ---  czogby [2015/03/31 18:01:28Z]
** Added macro UtAssert_IntegerCmpAbs
** Revision 1.2 2015/03/10 15:19:29EDT czogby 
** Add Missing Functionality to UT Assert Library
**
** Design Notes:
**    - All asserts evaluate a expression as TRUE or FALSE to determine if a unit test has
**      passed or failed.  TRUE means the test passed, FALSE means the test failed.
**    - All asserts return a boolen result to indicate the pass fail status.
**    - All asserts are implemented as macros to hide the __LINE__ and __FILE__ macros.
**    - All asserts must call the function UtAssert.
**
*/

#ifndef _utassert_
#define	_utassert_

/*
 * Includes
 */

#include "common_types.h"
#include "uttools.h"
#include <string.h>
#include <stdio.h>
#include <math.h>

/**
 * Define various types of messages that can be generated by a test.
 *
 * The order is significant for filtering; BSP's may elect to filter
 * messages based on the position within this list.  They should
 * be ordered in terms of relative importance from most to least severe.
 */
typedef enum
{
    UTASSERT_CASETYPE_NONE,          /**< Reserved value, No messages should be used with this */
    UTASSERT_CASETYPE_ABORT,         /**< Test sequence abort (major failure, cannot continue) */
    UTASSERT_CASETYPE_FAILURE,       /**< Test case failure status messages */
    UTASSERT_CASETYPE_TSF,           /**< Test Setup Failure (TSF) status messages */
    UTASSERT_CASETYPE_TTF,           /**< Test Teardown Failure (TTF) status messages */
    UTASSERT_CASETYPE_MIR,           /**< Manual Inspection Required (MIR) status messages */
    UTASSERT_CASETYPE_NA,            /**< Test Not Applicable (NA) status messages */
    UTASSERT_CASETYPE_BEGIN,         /**< Beginning of test status messages */
    UTASSERT_CASETYPE_END,           /**< End of test status messages */
    UTASSERT_CASETYPE_INFO,          /**< All other informational status messages */
    UTASSERT_CASETYPE_PASS,          /**< Test case passed (normal) status messages */
    UTASSERT_CASETYPE_DEBUG,         /**< Debugging messages */
    UTASSERT_CASETYPE_MAX            /**< Reserved value, No messages should be used with this */
} UtAssert_CaseType_t;

/**
 * Test Counter object
 * Summarizes counters for all case types
 */
typedef struct
{
    uint32 TestSegmentCount;
    uint32 TotalTestCases;
    uint32 CaseCount[UTASSERT_CASETYPE_MAX];
} UtAssert_TestCounter_t;


/*
 * Macro Definitions
 */

/* A simplified UtAssert that uses the expression itself as the description */
#define     UtAssert_Simple(Expression)      \
        UtAssert(Expression, #Expression, __FILE__, __LINE__)

/* Evaluates a expression as either TRUE or FALSE.  TRUE means the test passed, FALSE means the test failed. */
#define     UtAssert_True(Expression, ...) \
        UtAssertEx(Expression, UtAssert_GetContext(), __FILE__, __LINE__, __VA_ARGS__)

/* Evaluates a expression as either TRUE or FALSE.  TRUE means the test passed, FALSE means the test failed. */
#define     UtAssert_Bool(Expression, Description) \
        UtAssert(Expression, Description, __FILE__, __LINE__)

/* Asserts a test failure */
#define     UtAssert_Failed(...) \
        UtAssertEx(FALSE, UtAssert_GetContext(), __FILE__, __LINE__, __VA_ARGS__)

/* Compares two integers and determines if they are equal within a specified absolute tolerance. */
#define     UtAssert_IntegerCmpAbs(x, y, Tolerance, Description) \
                UtAssert((abs((x) - (y)) <= (Tolerance)), Description, __FILE__, __LINE__)

/* Compares two floating point numbers and determines if they are equal within a specified absolute tolerance. */
#define     UtAssert_DoubleCmpAbs(x, y, Tolerance, Description) \
                UtAssert((fabs((x) - (y)) <= (Tolerance)), Description, __FILE__, __LINE__)

/* Compares two floating point numbers and determines if they are equal within a specified relative tolerance. */
#define     UtAssert_DoubleCmpRel(x, y, Ratio, Description) \
                UtAssert((fabs((x) - (y))/(x) <= (Ratio)), Description, __FILE__, __LINE__)

/* Compares two strings and determines if they are equal. */
#define     UtAssert_StrCmp(String1, String2, Description) \
                UtAssert((strcmp(String1, String2) == 0), Description, __FILE__, __LINE__)

/* Compares at most Length characters of two strings and determines if they are equal. */
#define     UtAssert_StrnCmp(String1, String2, Length, Description) \
                UtAssert((strncmp(String1, String2, Length) == 0), Description, __FILE__, __LINE__)

/* Compares two regions of memory and determines if they are equal. */
#define     UtAssert_MemCmp(Memory1, Memory2, Length, Description) \
                UtAssert((memcmp(Memory1, Memory2, Length) == 0), Description, __FILE__, __LINE__)

/* Compares a region of memory to a static pattern and determines if they are equal.  Note: Use UtMemSet to
 * fill a region of memory with a static pattern. */
#define     UtAssert_MemCmpValue(Memory, Value, Length, Description) \
                UtAssert((UtMemCmpValue(Memory, Value, Length)), Description, __FILE__, __LINE__)

/* Compares a region of memory to a byte count pattern and determines if they are equal.  Note: Use UtMemFill to
 * fill a region of memory with a byte count pattern. */
#define     UtAssert_MemCmpCount(Memory, Length, Description) \
                UtAssert((UtMemCmpCount(Memory, Length)), Description, __FILE__, __LINE__)

/* Compares a region of memory with the contents of a binary file and determines if they are equal.  Note: Use
 * UtMem2BinFile to copy a region of memory to a binary file. */
#define     UtAssert_Mem2BinFileCmp(Memory, Filename, Description) \
                UtAssert((UtMem2BinFileCmp(Memory, Filename)), Description, __FILE__, __LINE__)

/* A wrapper around UtAssertEx that allows the user to specify the failure type and a more descriptive message */
#define     UtAssert_Type(Type,Expression,...)      \
                UtAssertEx(Expression, UTASSERT_CASETYPE_##Type, __FILE__, __LINE__, __VA_ARGS__)

/*
 * Exported Functions
 */

/* Returns the number of asserts that have passed. */
uint32      UtAssert_GetPassCount(void);

/* Returns the number of asserts that have failed. */
uint32      UtAssert_GetFailCount(void);

/* Returns the full status of UtAssert counters */
const UtAssert_TestCounter_t *UtAssert_GetCounters(void);

/* Begins a test Segment */
void UtAssert_BeginTest(const char *SegmentName);

/* Completes a test Segment */
void UtAssert_EndTest(void);

/* Sets the context of the current test, which is the default message type for UtAssert calls */
void UtAssert_SetContext(UtAssert_CaseType_t Context);

/* Sets the context of the current test, which is the default message type for UtAssert calls */
UtAssert_CaseType_t UtAssert_GetContext(void);

/* Base assert function.  All asserts must call this function. */
osalbool    UtAssert(osalbool Expression, const char *Description, const char *File, uint32 Line);

/*
 * Assert function with CaseType (supports MIR, TSF, NA in addition to FAIL).
 * Also supports printf-style message strings to allow more dynamic content in the messages
 */
osalbool    UtAssertEx(osalbool Expression, UtAssert_CaseType_t CaseType, const char *File, uint32 Line, const char *MessageFormat, ...) OS_PRINTF(5,6);

/*
 * Aborts the entire test
 * (for failures which going on is meaningless or impossible)
 */
void UtAssert_Abort(const char *Message);

/**
 * Output an informational message to the console/log file
 *
 * Just like the standard printf except it will output to the given status channel (see utassert.h)
 *
 * This calls into the UT BSP function to actually write the message
 * to the current output device.  This may be the console or a log file
 * or something else depending on what BSP is in use.
 */
void UtAssert_Message(uint8 MessageType, const char *File, uint32 Line, const char *Spec, ...) OS_PRINTF(4,5);


#endif
